/**
 * Created by ling on 2015/5/6.
 * action.js 是从LeeUI拷贝而来，任何再拷贝、再分发需要经过作者本人同意。并注明作者信息。
 * Author 王培梁
 * Email Ling.RayW@outlook.com
 */

(function (window, document, conf) {

    var action = window.action = {
        fn: {},
        handlers: [], // action自定义事件handler
        module: {},//控制中心，页面对象集合
        base: {},//基类或工具类
        pageInfo: {
            define: '',
            vals: null
        },
        event: {
            handlers: {},
            addHandler: function (type, handler) {
                if (typeof this.handlers[type] === 'undefined') {
                    this.handlers[type] = [];
                }
                this.handlers[type].push(handler);
            },
            fire: function (event) {
                if (!event.target) {
                    event.target = this;
                }
                if (this.handlers[event.type] instanceof Array) {
                    var handlers = this.handlers[event.type];
                    for (var i = 0, len = handlers.length; i < len; i++) {
                        handlers[i](event);
                    }
                }
            },

            /**
             * (移除注册的事件)
             *
             * @param type (事件类型)
             * @param handler (事件处理函数)
             */
            removeHandler: function (type, handler) {
                if (this.handlers[type] instanceof Array) {
                    var handlers = this.handlers[type], i = 0, len = handlers.length;
                    for (; i < len; i++) {
                        if (handlers[i] === handler) { break; }
                    }
                    handlers.splice(i, 1);
                }
            }
        },
        stringUtil: {
            isNull: function (str) {
                return !(typeof str === 'string' && str && str.replace(/(^\s*)|(\s*$)/g, ''));
            }
        },
        //--build:logger--
        logger: {
            toLength: function (str) {
                str = '    ' + str;
                var i = str.length;
                while (i < 125) {
                    str += ' ';
                    ++i;
                }
                return str;
            },
            log: function (define, instance) {
                var keys = Object.getOwnPropertyNames(instance),
                    output = '\n',
                    hr = '-----------------------------------------------------------------------------------------------------------------------------',
                    fnStr = '',
                    valStr = '',
                    line = '\n';
                for (var i = 0, len = keys.length; i < len; ++i) {
                    var name = keys[i];

                    if (typeof instance[name] === 'function')
                        fnStr += this.toLength(name) + line;
                    else
                        valStr += this.toLength(name + ' :') + '\n' + this.toLength('         => ' + instance[name]) + line;
                }

                output += this.toLength('Page Define');
                output += line;
                output += hr;
                output += line;
                output += this.toLength(define);
                output += line;
                output += hr;
                output += line;
                output += this.toLength('Val');
                output += line;
                output += hr;
                output += line;
                output += valStr;
                output += hr;
                output += line;
                output += this.toLength('Function');
                output += line;
                output += hr;
                output += line;
                output += fnStr;
                console.log('%c%s', "font:400 16px/1.6;color:#8FA1B2;background-color:rgb(20,23,26)", output);
            }
        },
        //--endbuild--
        /**
         * 功能:初始化页面信息
         */
        initPageInfo: function () {
            var defineElement = document.querySelector('[data-define]') || document.querySelector('x-foo-define');
            this.pageInfo.vals = document.querySelectorAll('val') || document.querySelectorAll('x-foo-val');
            if (defineElement instanceof HTMLElement) {
                this.pageInfo.define = defineElement.getAttribute('data-define');
            }
            return this.pageInfo;
        },

        /**
         * 功能:动态为page对象添加属性
         *
         * @param page{Object}
         * @param vals{NodeList}
         */
        initParams: function (page, vals) {
            var val = null,
                valAttr = '',
                valValue = '',
                valType = '';
            for (var i = 0, len = vals.length; i < len; ++i) {
                val = vals[i];
                if (val instanceof HTMLElement) {
                    valAttr = val.getAttribute('data-name');
                    valValue = val.getAttribute('data-value');
                    valType = val.getAttribute('data-type');

                    if (valAttr) {
                        page[valAttr] = valType === 'json' ? JSON.parse(valValue) : valValue;
                    }
                }
            }
        },
        /**
         * 功能:从控制中心取得基类或工具类
         * @param name{String}
         * @returns {Object}
         */
        fetch: function (name) {
            if (typeof this.base[name] === 'function') {
                var tempObj = this.base[name].apply(Object);
                this.base[name] = typeof tempObj === 'function' ? new tempObj() : tempObj;
            }
            return this.base[name];
        },

        /**
         * 功能:织入切面，主要用于测量用户function性能、调用、日志等信息
         *     生产环境可去掉些功能以提高性能
         *
         * @param page{Object}
         */
        handerFunction: function (page) {
            //--build:handerFunction--
            var keys = Object.getOwnPropertyNames(page.constructor.prototype);
            for (var i = 0, len = keys.length; i < len; ++i) {
                var funcName = keys[i], fn = page[funcName];
                if (typeof fn === 'function' && funcName !== 'constructor') {
                    page[funcName] = fn.around(funcName);
                }
            }
            //--endbuild--
            return page;
        },
        /**
         * 功能:提供能外部调用
         * 兼容1.0版本提供的API
         */
        loadImg: function () {
            var imgs = document.querySelectorAll('img[data-delay]');
            this.loadDelayImg(imgs);
        },
        /**
         * 功能:将图象的懒加载属性写入src属性，进行图象加载
         *
         * @param imgs{NodeList}
         */
        loadDelayImg: function (imgs) {
            Array.prototype.forEach.call(imgs, function (img) {
                if (img instanceof HTMLElement) {
                    //update by wpl 手动触发时，如果已经加载就跳过
                    if(img.getAttribute('load')){return;}

                    img.setAttribute('load', 'unload');
                    var src = img.getAttribute('data-delay');
                    img.addEventListener('load', function () {
                        img.setAttribute('load', 'loaded');
                        if (img.classList.contains('obj-contain') && !('objectFit' in img.style)) {
                            fitImg(img);
                        }
                    });
                    img.addEventListener('error', function () {
                        var defaultSrc = img.getAttribute('data-default');
                        img.setAttribute('load', 'error');

                        if (defaultSrc && defaultSrc !== img.getAttribute('src')) {
                            img.setAttribute('src', defaultSrc);
                        }
                    });
                    if (src)
                        img.setAttribute('src', src);
                }
            });
        },
        /**
         * 功能:检测img图象是否加载完成
         *
         * @param imgs{NodeList}
         * @returns {boolean}
         */
        delayImgLoaded: function (imgs) {
            for (var i = 0, len = imgs.length; i < len; ++i) {
                var img = imgs[i];
                if (img instanceof HTMLElement) {
                    var load = img.getAttribute('load');
                    if (load === 'unload')
                        return false;
                }
            }
            return true;
        },
        /***
         * 向页面添加script标签
         * @param src
         * @param callback
         * @param defer
         */
        appendScript: function (src, callback, defer) {
            if (this.stringUtil.isNull(src))
                return;

            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.setAttribute('src', src);
            if (defer) {
                script.setAttribute('defer', 'defer');
            }
            if (callback instanceof Function) {
                script.onload = function(event){
                    callback(event, script);
                };
            }
            document.body.appendChild(script);
        },
        /**
         * 动态加载
         * @param define
         */
        require: function (define) {
            var _this = this,
                current = conf[define];
            if (!current) return;

            var src = current.url + '?v=' + current.version;
            var scriptOnload = function (evt,script) {
                if (!script.readyState || script.readyState === "loaded" || script.readyState === "complete") {
                    console.log("Page js loaded! Event fire...");
                    _this.event.fire({ type: "invoke", message: "hello" });
                }
            };
            _this.appendScript(src, scriptOnload);
        },
        /**
         * 功能:组装define
         * @param name
         * @param require
         * @param target
         */
        buildModule: function (name, require, target) {
            /*var xxx = {
             require:['req1','req2'],
             target:function
             };*/
            var stringUtil = this.stringUtil,
                module = {
                    require: null,
                    target: null
                };
            if (!stringUtil.isNull(name) && target instanceof Function) {
                module.target = target;
                if (require instanceof Array) {
                    var reqs = [];
                    for (var index in require) {
                        //检测依赖的合法性
                        var arg = require[index];
                        if (!stringUtil.isNull(arg) && this.base.hasOwnProperty(arg)) {
                            reqs.push(arg);
                        } else {
                            throw new Error('依赖参数错误!');
                        }
                    }
                    if (reqs.length)
                        module.require = reqs;
                }
                this.module[name] = module;
            }
        },
        /**
         * * 功能:初始化Module
         * @param target
         * @param require
         * @returns {*}
         */
        initModule: function (target, require) {
            var args = [];
            if (!(target instanceof Function))
                throw new Error('非法模块调用!');
            if (require instanceof Array && require.length) {
                for (var index in require) {
                    var req = require[index];
                    args.push(this.fetch(req));
                }
            }
            var tempObj = target.apply(Object, args),
                instance = this.handerFunction(new tempObj());
            return instance;
        },
        /**
         * 功能：向action 注册page load事件
         * @param eventType
         * @param handler
         */
        registerHandlers: function (eventType, handler) {
            if (typeof eventType === 'string' && typeof handler === 'function' ) {
                if (this.handlers.indexOf(eventType) !== -1) throw new Error('事件:%s 已经注册!', eventType);
                this.handlers.push(eventType);
                this.event.addHandler(eventType,handler);
            }
        },
        /**
         * 功能： 在page 加载完后，广播事件
         */
        fireHandlers: function () {
            var handlers = this.handlers;
            for (var i = 0, len = handlers.length; i < len; ++i) {
                var eventType = handlers[i];
                this.event.fire({type: eventType, message: "Action page loaded!"})
            }
        }
    };

    /**
     * 功能:定义普通页面对象
     */
    window.define = function () {
        var args = arguments,
            length = args.length;
        if (length >= 2) {
            var temp,
                requires,
                defineName = args[0],
                arg1 = args[1],
                arg2 = length === 3 ? args[2] : null;
            if (arg1 instanceof Function)
                temp = arg1;
            if (arg2 instanceof Function)
                temp = arg2;
            if (arg1 instanceof Array)
                requires = arg1;
            if (!action.stringUtil.isNull(defineName))
                action.buildModule(defineName, requires, temp);
        }
    };

    /**
     * 功能:定义普通基类或工具类
     *
     * @param name{String}
     * @param target{Function}
     */
    var plugin = function (name, target) {
        if (typeof name === 'string' && /^object|function$/.test(typeof target) && '' !== name) {
            if (!action.base[name]) {
                action.base[name] = target;
                //action.handerFunction(action.base[name]);
            }
        }
    };
    window.base = plugin;
    window.plugin = plugin;

    /**
     * 功能:阻止事件冒泡
     *
     * @param evt{Event}
     * @returns {boolean}
     */
    window.stopEvent = function (evt) {
        evt = evt || window.event;
        if (evt.preventDefault) {
            evt.preventDefault();
            evt.stopPropagation();
        }
        if (evt.returnValue)
            evt.returnValue = false;
        if (evt.cancelBubble)
            evt.cancelBubble = true;
        return false;
    };


    /**
     * 初始化
     * 过程：1.检测x-foo-deine定义、读取x-foo-val和img延迟集合。
     *      2.如果页面定义了x-foo-deine元素，并且页面对象引用是合法存在控制中。将对象引用注入到全局page属性(window.page)。
     *      3.将x-foo-val集合注入到页面对象引用，即当前window.page上。
     *      4.调用当前页面引用(window.page)的ready和register方法。
     *      5.加载页面所有延迟加载img。
     *      5.检测页面所有延迟加载img集合是否加载完成，加载完成调用当前页面引用的imgReady方法。
     */
    var invoke = {
        pageInfo: action.pageInfo,
        invokePage: function () {
            if (this.pageInfo.define) {
                var defineModule = action.module[this.pageInfo.define];
                if (defineModule instanceof Object) {
                    window.page = window.page = action.initModule(defineModule.target, defineModule.require);
                    //注入页面key-value
                    if (this.pageInfo.vals) {
                        action.initParams(page, this.pageInfo.vals);
                    }
                    if (window.__pageVals) {
                        $.extend(page, window.__pageVals);
                    }
                    //--build:log--
                    if (!localStorage || localStorage.getItem('nolog') !== 'yes') {
                        action.logger.log(this.pageInfo.define, page);
                    }
                    //--endbuild--
                    //图片加载后调用
                    if ('function' === typeof page.imgReady) {
                        var delayImgs = document.querySelectorAll('img[data-delay]');
                        //1.5s检测一次
                        var check = self.setInterval(function () {
                            if (action.delayImgLoaded(delayImgs)) {
                                window.clearInterval(check);
                                page.imgReady();
                            }
                        }, 1500);
                    }

                    //模块调用入口
                    try {
                        if ('function' === typeof page.ready) { page.ready(); }
                        if ('function' === typeof page.register) { page.register(); }
                        action.fireHandlers();
                    } catch (e) {
                        window.console.error(e.message, e);
                    }
                }
            }
            return this;
        },
        execute: function () {
            invoke.invokePage();
        }
    };
    //添加事件处
    action.event.addHandler("invoke", invoke.execute);


    window.addEventListener('DOMContentLoaded', function load() {
        window.removeEventListener('DOMContentLoaded', load, false);
        var defineValue = action.initPageInfo().define;
        if (conf instanceof Object) {
            if (defineValue) { action.require(defineValue); }
        } else {
            invoke.invokePage();
        }
        //加载图片, 若有延迟选项则不加载
        if (!document.querySelector('x-foo-opt[data-name=deferImgLoad]')) {
            action.loadImg();
        }
    }, false);

    // 工具方法
    // 模拟object-fit: contain;
    function fitImg(img) {
        var sw, width = sw = img.scrollWidth, sh, height = sh = img.scrollHeight,
            nw = Math.max(img.naturalWidth, 1), nh = Math.max(img.naturalHeight, 1),
            widthRatio = sw / nw, heightRatio = sh / nh;
        if (widthRatio != 1 || heightRatio != 1) {
            if (widthRatio < heightRatio) {
                height = nh * widthRatio;
            } else {
                width = nw * heightRatio;
            }
            img.style.width = width + 'px';
            img.style.height = height + 'px';
            img.style.margin = (sh - height) / 2 + 'px ' + (sw - width) / 2 + 'px';
        }
    }
}(window, window.document, window.actionConfig));